#include <iostream>
#include <string>
#include <list>
#include <memory>

using std::cout;
using std::endl;
using std::string;
using std::list;
using std::unique_ptr;

class Observer
{
public:
    virtual void update(int status) = 0;
    virtual ~Observer() {}
};

class ConcreteObserverA
: public Observer
{
public:
    ConcreteObserverA(const string &name)
    : _name(name)
    {}

    virtual void update(int status) override
    {
        cout << "ConcreteObserverA name = " << _name 
             << "， 得到的状态 " << status << endl;
    }
private:
    string _name;
};

class ConcreteObserverB
: public Observer
{
public:
    ConcreteObserverB(const string &name)
    : _name(name)
    {}

    virtual void update(int status) override
    {
        cout << "ConcreteObserverB name = " << _name 
             << "， 得到的状态 " << status << endl;
    }
private:
    string _name;
};

class Subject
{
public:
    //添加观察者
    virtual void attach(Observer *pob)  = 0;
    //删除观察者
    virtual void detach(Observer *pob)  = 0;
    //发通知
    virtual void notify()  = 0;
    virtual ~Subject() {}
};

class ConcreteSubject
: public Subject
{
public:
    //添加观察者
    virtual void attach(Observer *pob) override
    {
        if(pob)
        {
            _obList.push_back(pob);
        }
    }

    //删除观察者
    virtual void detach(Observer *pob)  override
    {
        if(pob)
        {
            _obList.remove(pob);
        }
    }

    //发通知
    virtual void notify()  override
    {
        for(auto &ob : _obList)
        {
            //ob是抽象类型的指针，update是纯虚函数
            //必须体现出多态
            ob->update(_status);
        }
    }

    void setStatus(int status)
    {
        _status = status;
    }

    int getStatus() const
    {
        return _status;
    }
private:
    list<Observer *> _obList;//存放观察者的容器
    int _status;//状态
};

void test()
{
    //创建两个观察者对象
    unique_ptr<Observer> pa(new ConcreteObserverA("lili"));
    unique_ptr<Observer> pb(new ConcreteObserverB("lucy"));

    //创建具体的主题对象
    unique_ptr<ConcreteSubject> psub(new ConcreteSubject());

    //让观察者与主题之间产生关系
    psub->attach(pa.get());
    psub->attach(pb.get());

    //当主题的状态发生改变
    psub->setStatus(10);

    //主题开始发通知
    psub->notify();

    cout << endl << endl;
    //某个观察者pb不想关注主题的状态
    psub->detach(pb.get());
    
    //当主题的状态再次发生改变
    psub->setStatus(20);

    //主题再去发通知
    psub->notify();

}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

